/*all implements from go.h are here
 *if u want split this codes for core
 *using, u have to delete some variables
 *and functions which been implemented in
 *core funcions for connecting with GUI
 */

#include "go.h"
#include "step.h"
#include "record.h"
#include "settings.h"
#include "ai_algo/MoveGenerator.h"
#include <iostream>
#include <cstdio>
#include <cassert>


//初始化棋盘数据, 新的一盘棋
void Go::init()
{
    for(register int ix=1; ix<DIMENSION-1; ix++)
    {
        for(register int iy=1; iy<DIMENSION-1; iy++)
        {
            board[ix][iy]=VOID;
            block[ix][iy]=0;
            ko[ix][iy]=0;
            count[ix][iy]=0;
        }
    }
    for(int ix=0; ix<DIMENSION; ix++){
        board[ix][0]=GRID;
        board[ix][DIMENSION-1]=GRID;
        board[0][ix]=GRID;
        board[DIMENSION-1][ix]=GRID;
    }

    if(!(ser0.empty()))
    {
        ser0.erase(ser0.begin(),ser0.end());
    }
    if(!(all_block.empty()))
    {
        all_block.erase(all_block.begin(), all_block.end());
    }

    game_status = true;
    icl = true;
    whos_turn = BLACK;
    on_off = 0;
    block_index = 1;
    life = 0;

    cout << "棋盘初始化成功!" << endl;
}

/* 算气递归函数 只被init_getLiberty间接调用*/
int Go::getLiberty(int x, int y){
    int current = board[x][y]; // 要计算的位置的棋子状况, 只可能是-1或1
    if(current != BLACK && current != WHITE){
        cout << "错误, 此位置无棋子, 无法计算气!" << endl;
        return 0;
    }
    int temp_life(0); //暂时气数, 递归时用到
    if (!on_off){ //静态变量归零代码
        life=0;
        for (register int i=1;i<DIMENSION-1;i++){
            for (register int j=1;j<DIMENSION-1;j++){
                count[i][j]=0;
            }
        }
        on_off=1; //开关关闭, 因为递归时不需要归零
    }
    count[x][y] = 1; //将目前的位置标记为计算过的位置
    /* 计算该坐标上一格位置 */
    switch(board[x][y+1])
    {
        case 0: //若空且未重复计算则气+1
            //cout << "err!!" << endl;
            if(count[x][y+1]==0){
                temp_life++;
                count[x][y+1]=1;
            }
            break;
        default: //同色且未重复计算过则递归
            //cout << "count = " << count[x][y+1] << endl;
            if(board[x][y+1]==current && count[x][y+1]==0){
                life = getLiberty(x,y+1);
            }
    }
    /* 计算该坐标下一格位置 */
    switch(board[x][y-1])
    {
        case 0:
            if(count[x][y-1]==0){
                temp_life++;
                count[x][y-1]=1;
            }
            break;
        default:
            if(board[x][y-1]==current && count[x][y-1]==0){
                life = getLiberty(x,y-1);
            }
    }
    /* 计算该坐标左一格位置 */
    switch(board[x-1][y])
    {
        case 0:
            if(count[x-1][y]==0){
                temp_life++;
                count[x-1][y]=1;
            }
            break;
        default:
            if(board[x-1][y]==current && count[x-1][y]==0){
                life = getLiberty(x-1,y);
            }
    }
    /* 计算该坐标右一格位置 */
    switch(board[x+1][y])
    {
        case 0:
            if(count[x+1][y]==0){
                temp_life++;
                count[x+1][y]=1;
            }
            break;
        default:
            if(board[x+1][y]==current && count[x+1][y]==0){
                life = getLiberty(x+1,y);
            }
    }
    //cout << "current = [" << x << "] [" << y << "]" << endl;
    //cout << "life = " << life << endl;
    //cout << "temp_life = " << temp_life << endl;
    return life+temp_life;
}

/* 初始化局部静态变量的算气递归函数 */
int Go::init_getLiberty(int x, int y){
    on_off = 0;
    return getLiberty(x,y);
}

/* 棋块统计函数 只被init_getBlock间接调用*/
void Go::getBlock(int x, int y){

    coordinate coo;
    int current = board[x][y]; // 要计算的位置的棋子状况, 只可能是-1或1
    if(current != BLACK && current != WHITE){
        cout << "错误, 此位置无棋子, 无法统计棋块!" << endl;
        return;
    }

    if (!on_off){ //静态变量归零代码
        for (register int i=1;i<DIMENSION-1;i++){
            for (register int j=1;j<DIMENSION-1;j++){
                count[i][j]=0;
            }
        }
        ser0.erase(ser0.begin(), ser0.end()); //静态变量vector<pair<int,int>>的清零工作
        on_off=1; //开关关闭, 因为递归时不需要归零
    }

    count[x][y] = 1; //将目前的位置标记为计算过的位置

    /* 棋块建立,合并,删除等操作在此完成 */
    if(block[x][y]!=0){
        if(all_block.find(block[x][y])!=all_block.end()){
            map<int, series>::iterator iter = all_block.find(block[x][y]);
            all_block.erase(iter);
            //cout << "成功删除棋块" << block[x][y] << endl;
        }
    }
    block[x][y] = block_index; //将该位置棋子统计入当前棋块中, 会覆盖掉之前的棋块编号
    coo.first=x; coo.second=y;
    ser0.push_back(coo); //将坐标压入棋块容器中
    //cout << "坐标(" << x << "," << y << ")的棋子已被归入棋块" << block_index << "中." << endl;

    /* 统计该坐标上一格位置 */
    if(board[x][y+1]==current && count[x][y+1]==0){
        getBlock(x,y+1);
    }

    /* 统计该坐标下一格位置 */
    if(board[x][y-1]==current && count[x][y-1]==0){
        getBlock(x,y-1);
    }

    /* 计算该坐标左一格位置 */
    if(board[x-1][y]==current && count[x-1][y]==0){
        getBlock(x-1,y);
    }

    /* 计算该坐标右一格位置 */
    if(board[x+1][y]==current && count[x+1][y]==0){
        getBlock(x+1,y);
    }
}

/* 初始化局部静态变量的棋块统计函数 同时递增block_index */
void Go::init_getBlock(int x, int y){
    on_off = 0;
    //cout << "对棋块" << block_index << "进行统计......" << endl;
    getBlock(x,y); //获得零时棋块变量数据
    all_block.insert(map<int,series>::value_type(block_index,ser0)); //将棋块数据以及与之对应的棋块编号插入map容器中

    /* for testing...... */
    map<int,series>::iterator iter;
    iter = all_block.find(block_index);
    //cout << "当前索引棋块编号为\"" << iter->first << "\"" << endl;
    //cout << "属于当前棋块的棋子有......" << endl;
    for(vector<coordinate>::iterator it = (iter->second).begin(); it!=(iter->second).end(); it++){
        //cout << "坐标(" << it->first << "," << it->second << ")" << endl;
    }

    block_index++;
}

/* 提子及相关数据处理函数 */
void Go::take(int x, int y){
    /* 防错检查 */ /* 当嵌套与doit函数中时不需要多余的放错检查了, 已经确保这些问题不会发生 */
    //if(board[x][y]==VOID || board[x][y]==GRID){
        //cout << "此位置无子, 错误!" << endl;
        //return;
    //}
    //if(init_getLiberty(x,y)){
        //cout << "错误, 此位置棋子气不为0, 不可被提取!" << endl;
        //return;
    //}

    /* 数据处理 */
    map<int,series>::iterator iter = all_block.find(block[x][y]);

    /** 让子棋的话, 有可能iter=end(), 因为所让的棋子不会被编入棋块中 **/
    /** 用独立的判断分支将被让子提去, 如果被让子有邻子则不会发生这种情况, 因为被让子会被编入最新的邻子棋块中 **/
    if(iter == all_block.end())
    {
        tempStep->writeDeadStones(x,y);
        getSerie(x,y);
        board[x][y] = VOID;
    }
    /** 正常的提取棋块的步骤 **/
    else
    {
        vector<coordinate>::iterator it;
        for(it=(iter->second).begin();it!=(iter->second).end();it++){
            //cout << "提取坐标为(" << it->first << "," << it->second << ")的棋子" << endl;
            tempStep->writeDeadStones(it->first,it->second); //Step对象提子信息记录
            getSerie(it->first,it->second); //获得为图形界面准备的相关串
            board[it->first][it->second] = VOID; //棋盘状态归零
            block[it->first][it->second] = 0; //棋块编号归零
        }
        all_block.erase(iter); //从棋块库中删除被提取的棋块的信息
    }
}

/* 判断是否为提劫的函数 */
/* 需满足着子点无气(这个判断于doit函数内完成), 并且着子后能且仅能提取相邻的对方的一颗棋子, 方为打劫  */
/* 可不可以提劫是通过计数器block_index手数差以及一个ko[][]做为开劫的标识的变量的判断来实现 */
/* 仅嵌套于doit函数内 */
bool Go::ifKo(int x, int y){ //返回T 表示 目前可以提劫, 反之不可
    int k=0; //对应ko[][]数组的状态
    int kx=0,ky=0; //用于操作被记录的劫状态点的坐标
    int i = 0; //储存棋块编号的临时变量
    int opponent = whos_turn*(-1);
    if(board[x][y+1]==opponent){
        if(init_getLiberty(x,y+1)==0){
        i = block[x][y+1];
        k = ko[x][y+1];
        kx = x;
        ky = y+1;
        cout << "up" << endl;
        }
    }
    if(board[x][y-1]==opponent){
        if(init_getLiberty(x,y-1)==0){
        i = block[x][y-1];
        k = ko[x][y-1];
        kx = x;
        ky = y-1;
        cout << "down" << endl;
        }
    }
    if(board[x-1][y]==opponent){
        if(init_getLiberty(x-1,y)==0){
        i = block[x-1][y];
        k = ko[x-1][y];
        kx = x-1;
        ky = y;
        cout << "left" << endl;
        }
    }
    if(board[x+1][y]==opponent){
        if(init_getLiberty(x+1,y)==0){
        i = block[x+1][y];
        k = ko[x+1][y];
        kx = x+1;
        ky = y;
        cout << "right" << endl;
        }
    }
    //cout << "block_index-i=" << block_index-i << endl;
    /* 这个方法很不好, 临时用来判断第一次开劫, 需要用全局同行来判断方为上策<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
    if(k==0){
        //对ko[][]的修改被放入了switch()实际执行流程中, 使代码更安全
        //ko[kx][ky] = 1; //改变该点的状态
        //ko[x][y] = 1;
        cout << "开劫了!!!" << endl;
        return true;
    }
    if((block_index-i)!=1){ //是马上就回提吗? 手数只差1?
        //ko[x][y] = 1;
        //ko[kx][ky] = 1;
        return true;
    }
    else return false;
}

/* 主处理函数 */
void Go::doit(int x, int y){
    //enum status{NULL,forbidden,nl_mul_take,ke,take,no_take}
    int status = 0; //状态变量, 用以控制函数流程, 1表示禁着点, 2表示无气但可提取对方多个棋子, 3表示打劫, 4表示有气提子或不提子
    int opponent = whos_turn*(-1); //确定对手为黑还是白, 用于逻辑判断
    /** 这里有一个隐藏地比较深的逻辑错误, 也间接证明了这个判断打劫的方法的不安全性 **/
    /** 当ifko==eat==1时, 不一定肯定是打劫状态, 所有类似倒扑的棋形都会发生这个情况 **/
    int ifko = 0; //代表可以吃掉单个子的数量  |->
                 //                           | ->当且仅当ifko==eat==1时为有可能是打劫的状态
    int eat = 0; //代表可以吃掉的棋块数量     |->

    if(board[x][y]!=VOID){ //首先确定这个位子仍然为空
        cout << "此处不能着子!" << endl;
        return;
    }

    /* 判断此着属于那种状态 */
    board[x][y] = whos_turn; //虚拟着子
    int life = init_getLiberty(x,y);
    if(life!=0){
        status = 4; //状态4
    }
    else{
        status = 1; //假设为状态1
        if(board[x][y+1]==opponent){
            if(init_getLiberty(x,y+1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y+1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x][y-1]==opponent){
            if(init_getLiberty(x,y-1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y-1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x-1][y]==opponent){
            if(init_getLiberty(x-1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x-1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x+1][y]==opponent){
            if(init_getLiberty(x+1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x+1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        /** 如上所述这里需要进行额外的判断, 将类似倒扑的棋形归入状态2中即可 **/
        if(ifko==1 && eat==1){ //当打劫条件成立时, 进一步判断可否提劫
            if(board[x][y+1]!=whos_turn && board[x][y-1]!=whos_turn
               && board[x+1][y]!=whos_turn && board[x-1][y]!=whos_turn)
            {
                if(ifKo(x,y)){ //判断可否提劫
                    status = 3; //确定为状态3
                }
            }
            else status = 2; //这里是判定为倒扑状态
        }
        if(eat==0){
            status = 1; //确定为状态1
        }
        if(eat>1){
            status = 2; //确定为状态2
        }
    }

    board[x][y] = VOID; //撤销虚拟着子点的状态
    //cout << "确定当前着子点状态为" << status << endl; // for testing

    /** 之前的虚拟着子行为与is_allowed_move()相同, 不应该有改变成员数据的行为 **/
    /** 所有对成员数据的改变以及着子都在以下流程中完成 **/
    switch(status){ //进入不同状态相应的流程进行数据处理, 直至下一次落子之前
        case 1:
            cout << "此处为禁着点, 请重新着子!" << endl;
            return;
            cout << " " << endl;
        case 2:
            //cout << "我没有气, 但是可以提取对方多个棋子!" << endl;

            board[x][y] = whos_turn; //正式着子于棋盘上

            tempStep = new Step(block_index); //创建Step对象, 进行数据记录
            tempStep->writeColor(whos_turn); //Step对象棋子颜色记录
            tempStep->writeCoordinate(x,y); //Step对象坐标位置记录

            getSerie(x,y);
            if(board[x][y+1]==opponent){
                if(init_getLiberty(x,y+1)==0){
                    take(x,y+1);
                }
            }
            if(board[x][y-1]==opponent){
                if(init_getLiberty(x,y-1)==0){
                    take(x,y-1);
                }
            }
            if(board[x-1][y]==opponent){
                if(init_getLiberty(x-1,y)==0){
                    take(x-1,y);
                }
            }
            if(board[x+1][y]==opponent){
                if(init_getLiberty(x+1,y)==0){
                    take(x+1,y);
                }
            }
            init_getBlock(x,y); //将当前着子信息归入新棋块中

            /* Step对象二维数组相关数据以及all-block map数据拷贝 */
            tempStep->writeBoard(board);
            tempStep->writeBlock(block);
            tempStep->writeKo(ko);
            tempStep->writeAllBlock(&all_block);

            whos_turn*=(-1); //下次轮到对方着子
            break;

        case 3:
            //cout << "我没有气, 但是可以提劫!" << endl;
            tempStep = new Step(block_index); //创建Step对象, 进行数据记录
            board[x][y] = whos_turn; //正式着子于棋盘上
            ko[x][y] = 1;
            tempStep->writeColor(whos_turn); //Step对象棋子颜色记录
            tempStep->writeCoordinate(x,y); //Step对象坐标位置记录
            getSerie(x,y);
            //以下4个if条件有且仅有一个被满足
            if(board[x][y+1]==opponent){
                if(init_getLiberty(x,y+1)==0){
                    ko[x][y+1] = 1;
                    take(x,y+1);
                }
            }
            if(board[x][y-1]==opponent){
                if(init_getLiberty(x,y-1)==0){
                    ko[x][y-1] = 1;
                    take(x,y-1);
                }
            }
            if(board[x-1][y]==opponent){
                if(init_getLiberty(x-1,y)==0){
                    ko[x-1][y] = 1;
                    take(x-1,y);
                }
            }
            if(board[x+1][y]==opponent){
                if(init_getLiberty(x+1,y)==0){
                    ko[x+1][y] = 1;
                    take(x+1,y);
                }
            }
            init_getBlock(x,y);

            /* Step对象二维数组相关数据以及all-block map数据拷贝 */
            tempStep->writeBoard(board);
            tempStep->writeBlock(block);
            tempStep->writeKo(ko);
            tempStep->writeAllBlock(&all_block);

            whos_turn*=(-1);
            break;
        case 4:
            //cout << "我有气的当然可以着子!" << endl;
            tempStep = new Step(block_index); //创建Step对象, 进行数据记录
            board[x][y] = whos_turn; //正式着子于棋盘上
            tempStep->writeColor(whos_turn); //Step对象棋子颜色记录
            tempStep->writeCoordinate(x,y); //Step对象坐标位置记录
            getSerie(x,y);
            if(board[x][y+1]==opponent){
                if(init_getLiberty(x,y+1)==0){
                    take(x,y+1);
                }
            }
            if(board[x][y-1]==opponent){
                if(init_getLiberty(x,y-1)==0){
                    take(x,y-1);
                }
            }
            if(board[x-1][y]==opponent){
                if(init_getLiberty(x-1,y)==0){
                    take(x-1,y);
                }
            }
            if(board[x+1][y]==opponent){
                if(init_getLiberty(x+1,y)==0){
                    take(x+1,y);
                }
            }
            init_getBlock(x,y);

            /* Step对象二维数组相关数据以及all-block map数据拷贝 */
            tempStep->writeBoard(board);
            tempStep->writeBlock(block);
            tempStep->writeKo(ko);
            tempStep->writeAllBlock(&all_block);

            whos_turn*=(-1);
            break;
        default:
            cout << "未确定状态的棋子....." << endl;
            assert(0);
            break;
    }

    if(game_status)
    {
        record->addStep(tempStep); //将这个Step放入Record对象中完成数据记录
        latestStep = tempStep;
        tempLatestStep = tempStep;
    }
    else
    {
        if(icl)
        {
            icl = false;
        }
        record->deleteFrom(block_index-1); //会在复盘状态中每次倒退后的第一次着子时被执行
        record->addStepBU(tempStep);
    }

    //cout << "本次着子相关数据处理完毕!" << endl;
    //cout << "------------------------------------" << endl;
    return;
}

/* PASS功能实现的是没有着子行为但是所有相关的成员变量需要被操作 */
void Go::pass()
{
    tempStep = new Step(block_index++); //创建Step对象, 进行数据记录
    tempStep->writePass(); //将这个Step对象标记为具有PASS属性
    tempStep->writeColor(whos_turn); //Step对象棋子颜色记录
    //tempStep->writeCoordinate(x,y); //Step对象坐标位置记录, 对于PASS来说这个成员变量没有任何意义

    /* Step对象二维数组相关数据以及all-block map数据拷贝 */
    /* 这里拷贝的其实都是之前一手的数据 */
    tempStep->writeBoard(board);
    tempStep->writeBlock(block);
    tempStep->writeKo(ko);
    tempStep->writeAllBlock(&all_block);

    whos_turn*=(-1); //下次轮到对方着子

    record->addStep(tempStep); //将这个Step放入Record对象中完成数据记录
    latestStep = tempStep;
    tempLatestStep = tempStep;
}

/* 测试是否为禁着点, 尚未包含自填一眼等情况 */
bool Go::is_allowed_move(int x, int y)
{
    int status = 0; //状态变量, 用以控制函数流程, 1表示禁着点, 2表示无气但可提取对方多个棋子, 3表示打劫, 4表示有气提子或不提子
    int opponent = whos_turn*(-1); //确定对手为黑还是白, 用于逻辑判断
    int ifko = 0; //代表可以吃掉单个子的数量  |->
                 //                           | ->当且仅当ifko==eat==1时为有可能是打劫的状态
    int eat = 0; //代表可以吃掉的棋块数量     |->

    if(board[x][y]!=VOID){ //首先确定这个位子仍然为空
        return false;
    }

    /* 判断此着属于那种状态 */
    board[x][y] = whos_turn; //虚拟着子
    int life = init_getLiberty(x,y);
    if(life!=0){
        status = 4; //状态4
    }
    else{
        status = 1; //假设为状态1
        if(board[x][y+1]==opponent){
            if(init_getLiberty(x,y+1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y+1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x][y-1]==opponent){
            if(init_getLiberty(x,y-1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y-1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x-1][y]==opponent){
            if(init_getLiberty(x-1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x-1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x+1][y]==opponent){
            if(init_getLiberty(x+1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x+1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(ifko==1 && eat==1){ //当打劫条件成立时, 进一步判断可否提劫
            if(board[x][y+1]!=whos_turn && board[x][y-1]!=whos_turn
               && board[x+1][y]!=whos_turn && board[x-1][y]!=whos_turn)
            {
                if(ifKo(x,y)){ //判断可否提劫
                    status = 3; //确定为状态3
                }
            }
            else status = 2; //这里是判定为倒扑状态
        }
        if(eat==0){
            status = 1; //确定为状态1
        }
        if(eat>1){
            status = 2; //确定为状态2
        }
    }

    board[x][y] = VOID; //撤销虚拟着子点的状态

    if(status == 1) return false;
    else return true;
}

/** 暂且保留了与is_allowed_move一样的判断代码(实际不会用到) **/
bool Go::is_spec_allowed_move(int x, int y)
{
    int status = 0; //状态变量, 用以控制函数流程, 1表示禁着点, 2表示无气但可提取对方多个棋子, 3表示打劫, 4表示有气提子或不提子
    int opponent = whos_turn*(-1); //确定对手为黑还是白, 用于逻辑判断
    int ifko = 0; //代表可以吃掉单个子的数量  |->
                 //                           | ->当且仅当ifko==eat==1时为有可能是打劫的状态
    int eat = 0; //代表可以吃掉的棋块数量     |->

    if(board[x][y]!=VOID)
    {//在is_allowed_move基础上才被调用
    FILE * pFile;
    pFile = fopen("err.txt", "w");
    fprintf(pFile, "x=%d,y=%d", x, y);
    fclose(pFile);
    assert(0);
    }

    /* 判断此着属于那种状态 */
    board[x][y] = whos_turn; //虚拟着子
    int life = init_getLiberty(x,y);
    if(life!=0){
        status = 4; //状态4
        switch(life)
        {
                    /** 特殊判定一 **/
            case 1: /** 不下只有一口气并且同时满足以下两条件的棋 **/
                    /** 条件一: 这手棋吃不了对方的子 **/
                    /** 条件二: (倒扑)如果为单颗子,这颗子被对方吃掉以后, 对方那手棋的棋块气大于一 **/
                    /** 注意: 条件二会避免掉破眼位的手段 **/
                {
                    //检查条件一
                    if(board[x+1][y]==opponent)
                    {
                        if(init_getLiberty(x+1,y)==0) {board[x][y]=VOID; return true;}
                    }
                    if(board[x-1][y]==opponent)
                    {
                        if(init_getLiberty(x-1,y)==0) {board[x][y]=VOID; return true;}
                    }
                    if(board[x][y+1]==opponent)
                    {
                        if(init_getLiberty(x,y+1)==0) {board[x][y]=VOID; return true;}
                    }
                    if(board[x][y-1]==opponent)
                    {
                        if(init_getLiberty(x,y-1)==0) {board[x][y]=VOID; return true;}
                    }
                    //找到那口气的位置
                    int free_x=0,free_y=0;
                    if     (board[x+1][y]==VOID) {free_x=x+1; free_y=y;}
                    else if(board[x-1][y]==VOID) {free_x=x-1; free_y=y;}
                    else if(board[x][y+1]==VOID) {free_x=x; free_y=y+1;}
                    else if(board[x][y-1]==VOID) {free_x=x; free_y=y-1;}
                    if(free_x==0 && free_y==0)//这里表示走了一手3边为对方一边为己方的位置, 并且是不能提吃对手的
                                              //而且还是只有一口气
                    {
                        board[x][y] = VOID;
                        return false;
                    }
                    //检查条件二
                    if(board[x+1][y]!=whos_turn && board[x-1][y]!=whos_turn
                       && board[x][y+1]!=whos_turn && board[x][y-1]!=whos_turn)
                    {
                        board[free_x][free_y] = opponent;
                        if(init_getLiberty(free_x,free_y)==0) {board[free_x][free_y]=VOID;
                                                               board[x][y]=VOID; return true;}
                    }
                    //运行到这里判定为没有意义的着子, 不允许程序下
                    board[free_x][free_y] = VOID;
                    board[x][y] = VOID;
                    return false;
                }
            default: break;
        }
    }
    else{
        status = 1; //假设为状态1
        if(board[x][y+1]==opponent){
            if(init_getLiberty(x,y+1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y+1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x][y-1]==opponent){
            if(init_getLiberty(x,y-1)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x][y-1]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x-1][y]==opponent){
            if(init_getLiberty(x-1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x-1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(board[x+1][y]==opponent){
            if(init_getLiberty(x+1,y)==0){
                eat++;
                int sum = 0;
                map<int,series>::iterator iter = all_block.find(block[x+1][y]);
                vector<coordinate>::iterator it;
                for(it=(iter->second).begin();it!=(iter->second).end();it++){
                    sum++;
                }
                if(sum==1){
                    ifko++;
                }
                else status = 2; //假设为状态2
            }
        }
        if(ifko==1 && eat==1){ //当打劫条件成立时, 进一步判断可否提劫
            if(board[x][y+1]!=whos_turn && board[x][y-1]!=whos_turn
               && board[x+1][y]!=whos_turn && board[x-1][y]!=whos_turn)
            {
                if(ifKo(x,y)){ //判断可否提劫
                    status = 3; //确定为状态3
                }
            }
                               /** 特殊判定二 这里存疑 **/
            else {board[x][y]=VOID; return false;} //这里是判定为倒扑状态, 没有必要下这里吧???
        }
        if(eat==0){
            status = 1; //确定为状态1
        }
        if(eat>1){
            status = 2; //确定为状态2
        }
    }

    board[x][y] = VOID; //撤销虚拟着子点的状态

    if(status == 1) return false;
    else return true;
}

/* 处理让子规则下的内部数据并生成新的zeroStep以及给handicapsValue赋值 */
void Go::changeHandicaps(int i)
{
    handicapsValue = i;

    for(register int ix=1; ix<DIMENSION-1; ix++)
    {
        for(register int iy=1; iy<DIMENSION-1; iy++)
        {
            board[ix][iy]=VOID;
        }
    }

    switch(i)
    {
        case 1:
            if(zeroStep!=0) delete zeroStep;
            zeroStep = 0;
            whos_turn = BLACK;
            break;
        case 2:
            board[4][4] = BLACK; board[16][16] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 3:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 4:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 5:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK; board[10][10] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 6:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK; board[10][4] = BLACK; board[10][16] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 7:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK; board[10][4] = BLACK; board[10][16] = BLACK;
            board[10][10] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 8:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK; board[10][4] = BLACK; board[10][16] = BLACK;
            board[4][10] = BLACK; board[16][10] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;
        case 9:
            board[4][4] = BLACK; board[16][16] = BLACK; board[4][16] = BLACK;
            board[16][4] = BLACK; board[10][4] = BLACK; board[10][16] = BLACK;
            board[4][10] = BLACK; board[16][10] = BLACK; board[10][10] = BLACK;
            whos_turn = WHITE;
            zeroStep = new Step(0);
            zeroStep->writeBoard(board);
            break;

        default: break; //进入这里说明发生错误
    }
}

bool Go::load_changeHandicaps(Settings *gameSettings)
{
    handicapsValue = gameSettings->get_HA();
    series tempSeries = gameSettings->get_AB();

    if(!tempSeries.empty()) //因为.sgf文本格式有可能会出错, 列入由HA而没有AB, 所以这里进行检查
    {
        vector<coordinate>::iterator iter;
        for(iter=tempSeries.begin(); iter!=tempSeries.end(); iter++)
        {
            board[iter->first][iter->second] = BLACK;
        }
        whos_turn = WHITE;
        zeroStep = new Step(0);
        zeroStep->writeBoard(board);

        return true;
    }
    else return false;
}

/* 一个用于获取一个提供给图形界面的series的函数 实际植入在doit()以及take()中*/
void Go::getSerie(int x, int y)
{
    coordinate coo;
    coo.first = x;
    coo.second = y;

    drawSerie.push_back(coo);
}

/* 用于获得某一个Step对象的数据, 继而还原与这个Step对象相关的盘面数据 */
void Go::recoverStep(Step *step)
{
    if(step!=0)
    {
        block_index = step->getIndex() + 1; //
        whos_turn = -1 * (step->getColor()); //whos_turn为下一步棋的颜色, 所以要乘以-1
        //int getCoordinateX();
        //int getCoordinateY();
        //void getDeadStones(series *pdeadstones);
        step->getBoard(board);
        step->getKo(ko);
        step->getBlock(block);
        step->getAllBlock(&all_block);
    }
}

/*bool Go::ifDrawStone(int color, int x, int y)
{
    if(board[x][y] = color)
    {
        return false;
    }
    else return true;
}*/

/* 用做复盘时回到空的盘面时候的数据复制, 类似第零手棋, 与init()的区别仅是少了gamestatus的赋值 */
void Go::initZeroStep()
{
    //没有让子的情况
    if(zeroStep==0){
    for(register int ix=1; ix<DIMENSION-1; ix++)
    {
        for(register int iy=1; iy<DIMENSION-1; iy++)
        {
            board[ix][iy]=VOID;
            block[ix][iy]=0;
            ko[ix][iy]=0;
            count[ix][iy]=0;
        }
    }
    for(int ix=0; ix<DIMENSION; ix++){
        board[ix][0]=GRID;
        board[ix][DIMENSION-1]=GRID;
        board[0][ix]=GRID;
        board[DIMENSION-1][ix]=GRID;
    }

    if(!(ser0.empty()))
    {
        ser0.erase(ser0.begin(),ser0.end());
    }
    if(!(all_block.empty()))
    {
        all_block.erase(all_block.begin(), all_block.end());
    }

    whos_turn = BLACK;
    on_off = 0;
    block_index = 1;
    life = 0;
    }
    //让子的情况, 初始盘面有让子
    else
    {
        whos_turn = WHITE;
        on_off = 0;
        block_index = 1;
        life = 0;

        if(!(ser0.empty()))
        {
            ser0.erase(ser0.begin(),ser0.end());
        }
        if(!(all_block.empty()))
        {
            all_block.erase(all_block.begin(), all_block.end());
        }

        for(register int ix=1; ix<DIMENSION-1; ix++)
        {
            for(register int iy=1; iy<DIMENSION-1; iy++)
            {
                block[ix][iy]=0;
                ko[ix][iy]=0;
                count[ix][iy]=0;
            }
        }
        for(int ix=0; ix<DIMENSION; ix++){
            board[ix][0]=GRID;
            board[ix][DIMENSION-1]=GRID;
            board[0][ix]=GRID;
            board[DIMENSION-1][ix]=GRID;
        }

        //use zeroStep to recover the board[][]
        zeroStep->getBoard(board);
    }
}

/* 判断是否要覆盖掉latestStep, 内部实现有一个关联的成员变量作为开关 */
bool Go::ifCoverLatest()
{
    return icl;
}

/* 作用是改变ifCoverLatest变量, 用于复盘状态时的一些GUI设定 */
void Go::setIcl(bool b)
{
    icl = b;
}

void Go::coverLatestStep(Step *step)
{
    if(ifCoverLatest())
    {
        latestStep = step;
    }
}

coordinate Go::regret()
{
    coordinate coo;
    coo = (record->regretRecord());

    if(coo.first != ERROR)
    {
        latestStep = record->getLastStep(); //necessary!!!
        tempLatestStep = record->getLastStep();

        if(tempLatestStep == 0)
        {
            initZeroStep();
        }
        else recoverStep(tempLatestStep);

        return coo;
    }
    else
    {
        return coo;
    }
}

bool Go::ifMoveGenCreated()
{
    if(moveGen == 0) return false;
    else return true;
}

void Go::createMoveGenerator()
{
    moveGen = new MoveGenerator(this);
}

coordinate Go::moveGen_ABMinMax()
{
    assert(moveGen!=0); //have to create Generator first

    on_off = 0;

    return internal_moveGen_ABMinMax();
}

coordinate Go::internal_moveGen_ABMinMax()
{
    if(!on_off)
    {
        on_off = 1;
        _ban_moves.clear();
    }

    //额外的规则判定在这里
    coordinate coo = moveGen->runABMinMax();
    if(is_spec_allowed_move(coo.first, coo.second))/** FIXME: 这里如果一直是false, 会陷入无限循环 **/
    {
        return coo;
    }
    else
    {
        _ban_moves.push_back(coo);
        return internal_moveGen_ABMinMax();
    }
}

bool Go::if_ban_moves(int x, int y)
{
    vector<coordinate>::iterator iter;
    for(iter=_ban_moves.begin(); iter!=_ban_moves.end(); iter++)
    {
        if((*iter).first==x && (*iter).second==y) {return true;}
    }
    return false;
}

const series * Go::get_ban_moves()
{
    return &_ban_moves;
}

void Go::write_ban_moves(const series * s)
{
    _ban_moves = *s;
}

/* 开始新的棋局 用于没有界面下的cmd测试*/
void Go::newGame(){
    int xin=(DIMENSION-1)/2,yin=(DIMENSION-1)/2; //输入坐标 //结束机制, 如果输入2个0则程序结束
    init();
    cout << "游戏已经开始, 如果要结束游戏请输入坐标0,0, 祝您游戏愉快" << endl;
    cout << "-------------------------------------------------------" << endl;
    cout << "请黑棋首先着子......" << endl;
    cout << "请输入x的坐标:";
    cin >> xin;
    cout << "\n请输入y的坐标:";
    cin >> yin;
    cout << endl;
    while (xin!=0 && yin!=0){ //尚需增加一个位置检查机制, 防止坐标下在棋盘外面
        if(whos_turn==BLACK){
            cout << "当前为第" << block_index << "手, 黑棋落子于坐标(" << xin << "," << yin << ")" << endl;
        }
        else cout << "当前为第" << block_index << "手, 白棋落子于坐标(" << xin << "," << yin << ")" << endl;
        doit(xin,yin);
        cout << "请输入x的坐标:";
        cin >> xin;
        cout << "\n请输入y的坐标:";
        cin >> yin;
        cout << endl;
    }
    return;
}
